DYNAMO : Purge URL et Omniclass dans Familles .rfa avec script python

Etapes 01 : Diagnostic

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
import RevitServices
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument

# Mots-clés à détecter (insensible à la casse)
KEYWORDS = ["omniclass", "url", "http", "www",
            "manufacturer", "model", "assembly",
            "keynote", "description", "reference"]

def has_keyword(text):
    t = text.lower()
    return any(k in t for k in KEYWORDS)

def get_params(element):
    found = []
    for p in element.Parameters:
        try:
            if p.StorageType == StorageType.String:
                val = p.AsString()
                if val and val.strip() != "":
                    name = p.Definition.Name
                    # Garde si nom OU valeur contient un mot-clé
                    if has_keyword(name) or has_keyword(val):
                        found.append((name, val))
        except:
            pass
    return found

results = []

# Scan Family (niveau famille)
fam_collector = FilteredElementCollector(doc).OfClass(Family)
for fam in fam_collector:
    cat = fam.FamilyCategory.Name if fam.FamilyCategory else "—"
    params = get_params(fam)
    for (pname, pval) in params:
        results.append([
            fam.Name, "— (Family)", cat, pname, pval
        ])

# Scan FamilySymbol (niveau type)
sym_collector = FilteredElementCollector(doc).OfClass(FamilySymbol)
for fs in sym_collector:
    try:
        fam = fs.Family
        cat = fam.FamilyCategory.Name if fam.FamilyCategory else "—"
        params = get_params(fs)
        for (pname, pval) in params:
            results.append([
                fam.Name, fs.Name, cat, pname, pval
            ])
    except:
        pass

if results:
    OUT = [["Famille", "Type", "Catégorie", "Paramètre", "Valeur"]] + results
else:
    OUT = [["Aucun paramètre suspect trouvé"]]

Etapes 03 : Purge

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
import os
import tempfile

doc = DocumentManager.Instance.CurrentDBDocument

# Fermer toute transaction ouverte
try:
    TransactionManager.Instance.ForceCloseTransaction()
except:
    pass

TARGET_FAMILIES = [
    "AEX_CAN_RSX_MANCHON_ELECTRO",
    "AEX_CAN_RSX_MANCHON_THERMIQUE",
    "AEX_CAN_RSX_CAPE_DE_FERMETURE_GEBERIT",
    "AEX_ELE_RX_COUDE_RACCORD",
    "AEX_CAN_RSX_M_ELBOW_GENERIC",
    "AEX_CAN_RSX_M_CROSS_GENERIC",
    "AEX_CAN_RSX_M_COUPLING_GENERIC",
    "AEX_CAN_RSX_M_TEE_GENERIC",
    "AEX_CAN_RSX_M_TRANSITION_GENERIC",
    "AEX_CAN_RSX_FERMETURE_ATTENTE",
    "AEX_SAN_POMPE",
    "AEX_SAN_VASQUE",
    "AEX_PLA_HAIE",
    "AEX_PLA_HAIE_01",
    "AEX_PLA_HAIE_03",
    "AEX_PLA_ARBUSTE_16",
    "AEX_PLANT_Label",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_01",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_02",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_03",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_04",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_05",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_06",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_07",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_08",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_10",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_11",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_12",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_14",
    "AEX_PLANT_S_TOUS_Bushy02_ARBUSTE_15",
    "AEX_PLANT_S_TOUS_Bushy02_CEPEE_FEUILLU_PROJETE",
    "AEX_PLANT_T_TOUS_CONICAL02_ARBRE_CONIFERE_PROJETE",
    "AEX_PLANT_T_TOUS_CONICAL02_ARBRE_FEUILLU_PROJETE",
    "AEX_PLANT_T_TOUS_CONICAL02_ARBRE_FEUILLU_TRANSPLANTE",
    "AEX_PLANT_T_TOUS_CONICAL02_ARBUSTE_13",
    "AEX_PLANT_T_TOUS_CONICAL02_CEPEE_FEUILLU_PROJETE",
    "AEX_PLA_TIGE_01",
    "AEX_GDC_BARREAU_25MM",
    "AEX_GDC_BARREAU_190MM"
]

PARAMS_TO_PURGE = ["OmniClass Number", "OmniClass Title"]
tmp_dir = tempfile.gettempdir()

done = []
failed = []

fam_collector = list(FilteredElementCollector(doc).OfClass(Family))

for fam in fam_collector:
    if fam.Name not in TARGET_FAMILIES:
        continue

    fam_doc = None
    t = None
    t_reload = None

    try:
        # 1. Ouvrir la famille
        fam_doc = doc.EditFamily(fam)

        # 2. Modifier dans le doc famille
        t = Transaction(fam_doc, "Purge OmniClass")
        t.Start()

        for fs in FilteredElementCollector(fam_doc).OfClass(FamilySymbol):
            for pname in PARAMS_TO_PURGE:
                p = fs.LookupParameter(pname)
                if p and not p.IsReadOnly:
                    p.Set("")
            p1 = fs.get_Parameter(BuiltInParameter.OMNICLASS_CODE)
            p2 = fs.get_Parameter(BuiltInParameter.OMNICLASS_DESCRIPTION)
            if p1 and not p1.IsReadOnly: p1.Set("")
            if p2 and not p2.IsReadOnly: p2.Set("")

        t.Commit()

        # 3. Sauvegarder en .rfa temporaire
        rfa_path = os.path.join(tmp_dir, fam.Name + ".rfa")
        save_opt = SaveAsOptions()
        save_opt.OverwriteExistingFile = True
        fam_doc.SaveAs(rfa_path, save_opt)
        fam_doc.Close(False)
        fam_doc = None

        # 4. Recharger dans le projet — pas de Family() vide
        t_reload = Transaction(doc, "Reload " + fam.Name)
        t_reload.Start()
        doc.LoadFamily(rfa_path)
        t_reload.Commit()

        done.append(fam.Name)

    except Exception as e:
        try:
            if t and t.HasStarted() and not t.HasEnded():
                t.RollBack()
        except: pass
        try:
            if t_reload and t_reload.HasStarted() and not t_reload.HasEnded():
                t_reload.RollBack()
        except: pass
        try:
            if fam_doc:
                fam_doc.Close(False)
        except: pass

        failed.append(fam.Name + " — " + str(e))

OUT = ["=== TRAITÉS (" + str(len(done)) + ") ==="] + done + \
      ["", "=== ÉCHECS (" + str(len(failed)) + ") ==="] + failed

NOTE : Workflow complet en 3 étapes :

  1. Lance le diagnostic → note les familles avec OmniClass/URL

  2. Copie ces noms dans TARGET_FAMILIES du script 2

  3. Lance le script 2→ vérifie 0 échecs → relance le diagnostic pour confirmer → sauvegarde Revit

Suivant
Suivant

De petits pas pour de grands changements